package cn.actoncode.boot.framework.security.core.filter;

import cn.actoncode.boot.framework.common.enums.UserTypeEnum;
import cn.actoncode.boot.framework.common.pojo.CommonResult;
import cn.actoncode.boot.framework.common.util.servlet.ServletUtils;
import cn.actoncode.boot.framework.security.core.LoginUser;
import cn.actoncode.boot.framework.security.core.util.JwtUtil;
import cn.actoncode.boot.framework.security.core.util.SecurityFrameworkUtils;
import cn.actoncode.boot.framework.web.core.handler.GlobalExceptionHandler;
import cn.actoncode.boot.module.ai.api.user.MemberUserApi;
import cn.actoncode.boot.module.member.api.user.dto.LoginUserDTO;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.exceptions.JWTVerificationException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import static cn.actoncode.boot.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
import static cn.actoncode.boot.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * Token 过滤器，验证 token 的有效性
 * 验证通过后，获得 {@link LoginUser} 信息，并加入到 Spring Security 上下文
 *
 * @author bin
 */
@Slf4j
@RequiredArgsConstructor
public class TokenAuthenticationFilter extends OncePerRequestFilter {

    private final GlobalExceptionHandler globalExceptionHandler;

    private final MemberUserApi userApi;

    @Override
    @SuppressWarnings("NullableProblems")
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("token");
        if (StrUtil.isNotEmpty(token)) {
            try {
                // 1 基于 token 构建登录用户
                LoginUser loginUser = buildLoginUserByToken(token, response);

                // 2. 设置当前用户
                if (loginUser != null) {
                    SecurityFrameworkUtils.setLoginUser(loginUser, request);
                }
            } catch (Throwable ex) {
                CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);
                ServletUtils.writeJSON(response, result);
                return;
            }
        }

        // 继续过滤链
        chain.doFilter(request, response);
    }

    private LoginUser buildLoginUserByToken(String token, HttpServletResponse response) {
        try {

            // 从token中获得用户id
            String userId = JwtUtil.getSubject(token);
            Integer userType = JwtUtil.getClaim(token, "type").asInt();
            if (null == userId) {
                return null;
            }
            LoginUser loginUser = new LoginUser();
            if (null == userType || userType == UserTypeEnum.MEMBER.getValue()) {
                LoginUserDTO loginUserDTO = userApi.getLoginUser(Long.valueOf(userId));
                Long llts = JwtUtil.getClaim(token, "llts").asLong();
                if (!loginUserDTO.getLlts().equals(llts)) {
                    throw exception(UNAUTHORIZED);
                }
                loginUser.setUserId(loginUserDTO.getUserId())
                        .setName(loginUserDTO.getName()).setSalt(loginUserDTO.getSalt());
            }

            // 校验token
            JwtUtil.verifyToken(token, loginUser.getSalt());
            // 构建登录用户
            return loginUser;
        } catch (JWTVerificationException e){
            log.info(e.getMessage());
            throw exception(UNAUTHORIZED);
        } catch (RuntimeException e) {
            return null;
        }
    }

}
